﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using WebAppIdentity.DbContext;
using WebAppIdentity.Migrations;
using WebAppIdentity.Request;
using WebAppIdentity.Response;

namespace WebAppIdentity.Services
{
	public class UserService : IUserService
	{
		private readonly JwtSettings _jwtSettings;
		private readonly UserManager<AppUser> _userManager;
		private readonly UserDbContext _appDbContext;
		private readonly SigningCredentials _signingCredentials;
		private readonly RsaSecurityKey _securityKey;
		public UserService(JwtSettings jwtSettings, UserManager<AppUser> userManager, UserDbContext appDbContext,
			IConfiguration configuration, SigningCredentials signingCredentials, RsaSecurityKey rsaSecurityKey)
		{
			_jwtSettings = jwtSettings;
			_userManager = userManager;
			_appDbContext = appDbContext;
			_signingCredentials = signingCredentials;
			_securityKey = rsaSecurityKey;
		}

		public async Task<TokenResult> LoginAsync(string username, string password)
		{
			var existingUser = await _userManager.FindByNameAsync(username);
			if (existingUser == null)
			{
				return new TokenResult()
				{
					Errors = new[] { "user does not exist!" }, //用户不存在
				};
			}
			var isCorrect = await _userManager.CheckPasswordAsync(existingUser, password);
			if (!isCorrect)
			{
				return new TokenResult()
				{
					Errors = new[] { "wrong user name or password!" }, //用户名或密码错误
				};
			}
			return await GenerateJwtToken(existingUser);
		}

		public async Task<TokenResult> RefreshTokenAsync(string token, string refreshToken)
		{
			var claimsPrincipal = GetClaimsPrincipalByToken(token);
			if (claimsPrincipal == null)
			{
				// 无效的token...
				return new TokenResult()
				{
					Errors = new[] { "1: Invalid request!" },
				};
			}

			var expiryDateUnix =
				long.Parse(claimsPrincipal.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Exp).Value);
			var expiryDateTimeUtc = UnixTimeToDateTime(expiryDateUnix);
			if (expiryDateTimeUtc > DateTime.UtcNow)
			{
				// token未过期...
				return new TokenResult()
				{
					Errors = new[] { "2: Invalid request!" },
				};
			}

			var jti = claimsPrincipal.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Jti).Value;

			var storedRefreshToken =
				await _appDbContext.RefreshTokens.SingleOrDefaultAsync(x => x.Token == refreshToken);
			if (storedRefreshToken == null)
			{
				// 无效的refresh_token...
				return new TokenResult()
				{
					Errors = new[] { "3: Invalid request!" },
				};
			}

			if (storedRefreshToken.ExpiryTime < DateTime.UtcNow)
			{
				// refresh_token已过期...
				return new TokenResult()
				{
					Errors = new[] { "4: Invalid request!" },
				};
			}

			if (storedRefreshToken.Invalidated)
			{
				// refresh_token已失效...
				return new TokenResult()
				{
					Errors = new[] { "5: Invalid request!" },
				};
			}

			if (storedRefreshToken.Used)
			{
				// refresh_token已使用...
				return new TokenResult()
				{
					Errors = new[] { "6: Invalid request!" },
				};
			}

			if (storedRefreshToken.JwtId != jti)
			{
				// refresh_token与此token不匹配...
				return new TokenResult()
				{
					Errors = new[] { "7: Invalid request!" },
				};
			}

			storedRefreshToken.Used = true;
			await _appDbContext.SaveChangesAsync();

			var dbUser = await _userManager.FindByIdAsync(storedRefreshToken.UserId.ToString());
			if (dbUser == null)
			{
				return new TokenResult()
				{
					Errors = new[] { "7: Invalid request!" },
				};
			}
			return await GenerateJwtToken(dbUser);
		}

		public static DateTime UnixTimeToDateTime(long time)
		{
			// Unix 时间戳是自1970年1月1日以来的秒数
			// 转换时需要加上 UTC 时区偏移
			DateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(time).UtcDateTime;
			return dateTime;
		}


		private ClaimsPrincipal? GetClaimsPrincipalByToken(string token)
		{
			return GetClaimsPrincipalByRsaToken(token);//使用非对称加密的逻辑验证token
			try
			{
				var tokenValidationParameters = new TokenValidationParameters
				{
					ValidateIssuer = false,
					ValidateAudience = false,
					ValidateIssuerSigningKey = true,
					IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_jwtSettings.SecurityKey)),
					ClockSkew = TimeSpan.Zero,
					ValidateLifetime = false // 不验证过期时间！！！
				};

				var jwtTokenHandler = new JwtSecurityTokenHandler();

				var claimsPrincipal =
					jwtTokenHandler.ValidateToken(token, tokenValidationParameters, out var validatedToken);

				var validatedSecurityAlgorithm = validatedToken is JwtSecurityToken jwtSecurityToken
												 && jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256,
													 StringComparison.InvariantCultureIgnoreCase);

				return validatedSecurityAlgorithm ? claimsPrincipal : null;
			}
			catch
			{
				return null;
			}
		}

		/// <summary>
		/// 获取非对称加密token
		/// </summary>
		/// <param name="token"></param>
		/// <returns></returns>
		private ClaimsPrincipal? GetClaimsPrincipalByRsaToken(string token)
		{


			var tokenValidationParameters = new TokenValidationParameters
			{
				ValidateIssuer = false,
				ValidateAudience = false,
				ValidateIssuerSigningKey = true,
				//IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.SecurityKey)),//使用对称加密
				IssuerSigningKey = _securityKey,//使用公钥解签
				ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256, SecurityAlgorithms.Aes128CbcHmacSha256 },//使用公钥解签
				TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("abc111111111111111111111111111111cba")),//  token解密密钥 jwe解密
				ClockSkew = TimeSpan.Zero,
				ValidateLifetime = false
			};

			var tokenHandler = new JwtSecurityTokenHandler();
			// 验证 JWT
			try
			{
				var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var validatedToken);
				return principal;
			}
			catch (SecurityTokenExpiredException)
			{
				Console.WriteLine("JWT has expired.");
			}
			catch (SecurityTokenInvalidSignatureException)
			{
				Console.WriteLine("JWT signature is invalid.");
			}
			catch (Exception ex)
			{
				Console.WriteLine("JWT validation failed: " + ex.Message);
			}
			return null;
		}

		public async Task<TokenResult> RegisterAsync(string username, string password, string address)
		{
			var existingUser = await _userManager.FindByNameAsync(username);
			if (existingUser != null)
			{
				return new TokenResult()
				{
					Errors = new[] { "user already exists!" }, //用户已存在
				};
			}
			var newUser = new AppUser() { UserName = username, Address = address };
			var isCreated = await _userManager.CreateAsync(newUser, password);
			if (!isCreated.Succeeded)
			{
				return new TokenResult()
				{
					Errors = isCreated.Errors.Select(p => p.Description)
				};
			}
			return await GenerateJwtToken(newUser);
		}

		private async Task<TokenResult> GenerateJwtToken(AppUser user)
		{
			#region 对称加密			
			//var key = Encoding.ASCII.GetBytes(_jwtSettings.SecurityKey);
			//var tokenDescriptor = new SecurityTokenDescriptor
			//{
			//	Subject = new ClaimsIdentity(new[]
			//	{
			//		new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
			//		new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString())
			//	}),
			//	IssuedAt = DateTime.UtcNow,
			//	NotBefore = DateTime.UtcNow,
			//	Expires = DateTime.UtcNow.Add(_jwtSettings.ExpiresIn),
			//	SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
			//		SecurityAlgorithms.HmacSha256Signature)
			//};
			//var jwtTokenHandler = new JwtSecurityTokenHandler();
			//var securityToken = jwtTokenHandler.CreateToken(tokenDescriptor);
			//var token = jwtTokenHandler.WriteToken(securityToken);
			#endregion

			#region 非对称加密
			// 创建 RSA 密钥 

			var tokenDescriptor = new SecurityTokenDescriptor
			{
				Subject = new ClaimsIdentity(new[]
				{
					new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
					new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString())
				}),
				IssuedAt = DateTime.UtcNow,
				NotBefore = DateTime.UtcNow,
				Expires = DateTime.UtcNow.Add(_jwtSettings.ExpiresIn),
				SigningCredentials = _signingCredentials//非对称加密
				,
				EncryptingCredentials = new EncryptingCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("abc111111111111111111111111111111cba")), JwtConstants.DirectKeyUseAlg, SecurityAlgorithms.Aes128CbcHmacSha256)
			};
			var tokenHandler = new JwtSecurityTokenHandler();
			var securityToken = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
			var token = tokenHandler.WriteToken(securityToken);

			#endregion

			//创建refreshtoken
			var refreshToken = new RefreshToken()
			{
				JwtId = securityToken.Id,
				UserId = user.Id,
				CreationTime = DateTime.UtcNow,
				ExpiryTime = DateTime.UtcNow.AddMonths(6),
				Token = GenerateRandomNumber()
			};

			await _appDbContext.RefreshTokens.AddAsync(refreshToken);
			await _appDbContext.SaveChangesAsync();

			return new TokenResult()
			{
				AccessToken = token,
				TokenType = "Bearer",
				RefreshToken = refreshToken.Token,
				ExpiresIn = (int)_jwtSettings.ExpiresIn.TotalSeconds
			};
		}
		private string GenerateRandomNumber(int len = 32)
		{
			var randomNumber = new byte[len];
			using var rng = RandomNumberGenerator.Create();
			rng.GetBytes(randomNumber);
			return Convert.ToBase64String(randomNumber);
		}

		public async Task<BaseResponse> ModifyPassword(ModifyPasswordRequest request, string? token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return new BaseResponse()
				{
					Errors = new[] { "1: 未获取到token!" },
				};
			}
			var claimsPrincipal = GetClaimsPrincipalByToken(token);
			if (claimsPrincipal == null)
			{
				// 无效的token...
				return new BaseResponse()
				{
					Errors = new[] { "1: Invalid request!" },
				};
			}

			var existingUser = await _userManager.FindByNameAsync(request.Username);
			if (existingUser == null)
			{
				return new BaseResponse()
				{
					Errors = new[] { "user is not exists!" }, //用户已存在
				};
			}

			var result = await _userManager.ChangePasswordAsync(existingUser, request.Password, request.NewPassword);
			if (!result.Succeeded)
			{
				return new BaseResponse()
				{
					Errors = result.Errors?.Select(p => p.Description)
				};
			}


			var jti = claimsPrincipal.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Jti).Value;
			var storedRefreshToken =
				await _appDbContext.RefreshTokens.SingleOrDefaultAsync(x => x.JwtId == jti);
			if (storedRefreshToken != null)
			{
				storedRefreshToken.Invalidated = true;
				await _appDbContext.SaveChangesAsync();
			}

			return new BaseResponse() { };
		}
	}
}
